Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
react-dropzone
Advanced tools
The react-dropzone npm package is a simple and highly customizable dropzone component for React applications. It allows users to drag and drop files into an area of a web page or click to select files through the file explorer. It is designed to provide developers with a flexible and easy-to-use interface for handling file uploads.
Basic File Drop
This feature allows users to create a basic dropzone area where files can be dragged and dropped or selected through a file dialog.
import React from 'react';
import { useDropzone } from 'react-dropzone';
function BasicDropzone() {
const { getRootProps, getInputProps } = useDropzone();
return (
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
);
}
export default BasicDropzone;
Accepting Specific File Types
This feature allows developers to specify which file types the dropzone will accept, limiting the user to only select or drag those types.
import React from 'react';
import { useDropzone } from 'react-dropzone';
function SpecificTypeDropzone() {
const { getRootProps, getInputProps } = useDropzone({
accept: 'image/*'
});
return (
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>Drag 'n' drop some images here, or click to select images</p>
</div>
);
}
export default SpecificTypeDropzone;
Styling Dropzone Based on Drag State
This feature allows developers to apply different styles to the dropzone depending on whether files are being dragged over it.
import React from 'react';
import { useDropzone } from 'react-dropzone';
function StyledDropzone() {
const { getRootProps, getInputProps, isDragActive } = useDropzone();
return (
<div {...getRootProps()} style={{
border: '2px dashed #eeeeee',
backgroundColor: isDragActive ? '#e0e0e0' : '#fafafa',
padding: '20px'
}}>
<input {...getInputProps()} />
{
isDragActive ?
<p>Drop the files here ...</p> :
<p>Drag 'n' drop some files here, or click to select files</p>
}
</div>
);
}
export default StyledDropzone;
Handling File Previews
This feature allows developers to handle file previews by creating image thumbnails for dropped files.
import React, { useState } from 'react';
import { useDropzone } from 'react-dropzone';
function FilePreviewDropzone() {
const [files, setFiles] = useState([]);
const { getRootProps, getInputProps } = useDropzone({
onDrop: acceptedFiles => {
setFiles(acceptedFiles.map(file => Object.assign(file, {
preview: URL.createObjectURL(file)
})));
}
});
const images = files.map(file => (
<div key={file.name}>
<img src={file.preview} style={{ width: '200px' }} alt='preview' />
</div>
));
return (
<section className='container'>
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
<aside>
<h4>Files</h4>
{images}
</aside>
</section>
);
}
export default FilePreviewDropzone;
Dropzone is a standalone JavaScript library that provides drag-and-drop file uploads with image previews. It's more feature-rich out of the box compared to react-dropzone, but it's not a React component by default, which means it might require additional integration effort in React applications.
React Dropzone Uploader is a React component that provides a dropzone as well as file previews and upload status. It offers more built-in features for handling uploads compared to react-dropzone, but it might be less flexible if you need to heavily customize the upload behavior.
FilePond is a flexible and fun JavaScript file upload library that can be turned into a React component using react-filepond. It provides a rich set of features like image optimization, file validation, and multiple file handling. It's a more comprehensive solution compared to react-dropzone but may be heavier if you only need a simple dropzone.
Simple React hook to create a HTML5-compliant drag'n'drop zone for files.
Documentation and examples at https://react-dropzone.js.org. Source code at https://github.com/react-dropzone/react-dropzone/.
Install it from npm and include it in your React build process (using Webpack, Browserify, etc).
npm install --save react-dropzone
or:
yarn add react-dropzone
You can either use the hook:
import React, {useCallback} from 'react'
import {useDropzone} from 'react-dropzone'
function MyDropzone() {
const onDrop = useCallback(acceptedFiles => {
// Do something with the files
}, [])
const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop})
return (
<div {...getRootProps()}>
<input {...getInputProps()} />
{
isDragActive ?
<p>Drop the files here ...</p> :
<p>Drag 'n' drop some files here, or click to select files</p>
}
</div>
)
}
IMPORTANT: Under the hood, this lib makes use of hooks, therefore, using it requires React >= 16.8
.
Or the wrapper component for the hook:
import React from 'react'
import Dropzone from 'react-dropzone'
<Dropzone onDrop={acceptedFiles => console.log(acceptedFiles)}>
{({getRootProps, getInputProps}) => (
<section>
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
</section>
)}
</Dropzone>
Warning: On most recent browsers versions, the files given by onDrop
won't have properties path
or fullPath
, see this SO question and this issue.
Furthermore, if you want to access file contents you have to use the FileReader API:
import React, {useCallback} from 'react'
import {useDropzone} from 'react-dropzone'
function MyDropzone() {
const onDrop = useCallback((acceptedFiles) => {
acceptedFiles.forEach((file) => {
const reader = new FileReader()
reader.onabort = () => console.log('file reading was aborted')
reader.onerror = () => console.log('file reading has failed')
reader.onload = () => {
// Do whatever you want with the file contents
const binaryStr = reader.result
console.log(binaryStr)
}
reader.readAsArrayBuffer(file)
})
}, [])
const {getRootProps, getInputProps} = useDropzone({onDrop})
return (
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
)
}
The dropzone property getters are just two functions that return objects with properties which you need to use to create the drag 'n' drop zone.
The root properties can be applied to whatever element you want, whereas the input properties must be applied to an <input>
:
import React from 'react'
import {useDropzone} from 'react-dropzone'
function MyDropzone() {
const {getRootProps, getInputProps} = useDropzone()
return (
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
)
}
Note that whatever other props you want to add to the element where the props from getRootProps()
are set, you should always pass them through that function rather than applying them on the element itself.
This is in order to avoid your props being overridden (or overriding the props returned by getRootProps()
):
<div
{...getRootProps({
onClick: event => console.log(event)
})}
/>
In the example above, the provided {onClick}
handler will be invoked before the internal one, therefore, internal callbacks can be prevented by simply using stopPropagation.
See Events for more examples.
Important: if you ommit rendering an <input>
and/or binding the props from getInputProps()
, opening a file dialog will not be possible.
Both getRootProps
and getInputProps
accept a custom refKey
(defaults to ref
) as one of the attributes passed down in the parameter.
This can be useful when the element you're trying to apply the props from either one of those fns does not expose a reference to the element, e.g.:
import React from 'react'
import {useDropzone} from 'react-dropzone'
// NOTE: After v4.0.0, styled components exposes a ref using forwardRef,
// therefore, no need for using innerRef as refKey
import styled from 'styled-components'
const StyledDiv = styled.div`
// Some styling here
`
function Example() {
const {getRootProps, getInputProps} = useDropzone()
<StyledDiv {...getRootProps({ refKey: 'innerRef' })}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</StyledDiv>
}
If you're working with Material UI and would like to apply the root props on some component that does not expose a ref, use RootRef:
import React from 'react'
import {useDropzone} from 'react-dropzone'
import RootRef from '@material-ui/core/RootRef'
function PaperDropzone() {
const {getRootProps, getInputProps} = useDropzone()
const {ref, ...rootProps} = getRootProps()
<RootRef rootRef={ref}>
<Paper {...rootProps}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</Paper>
</RootRef>
}
Important: do not set the ref
prop on the elements where getRootProps()
/getInputProps()
props are set, instead, get the refs from the hook itself:
import React from 'react'
import {useDropzone} from 'react-dropzone'
function Refs() {
const {
getRootProps,
getInputProps,
rootRef, // Ref to the `<div>`
inputRef // Ref to the `<input>`
} = useDropzone()
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
}
If you're using the <Dropzone>
component, though, you can set the ref
prop on the component itself which will expose the {open}
prop that can be used to open the file dialog programmatically:
import React, {createRef} from 'react'
import Dropzone from 'react-dropzone'
const dropzoneRef = createRef()
<Dropzone ref={dropzoneRef}>
{({getRootProps, getInputProps}) => (
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
)}
</Dropzone>
dropzoneRef.open()
Important: react-dropzone
makes some of its drag 'n' drop callbacks asynchronous to enable promise based getFilesFromEvent()
functions. In order to properly test this, you may want to utilize a helper function to run all promises like this:
const flushPromises = () => new Promise(resolve => setImmediate(resolve))
Example with react-testing-library:
import React from 'react'
import Dropzone from 'react-dropzone'
import { fireEvent, render } from 'react-testing-library'
test('invoke onDragEnter when dragenter event occurs', async () => {
const file = new File([
JSON.stringify({ping: true})
], 'ping.json', { type: 'application/json' })
const data = mockData([file])
const onDragEnter = jest.fn()
const ui = (
<Dropzone onDragEnter={onDragEnter}>
{({ getRootProps, getInputProps }) => (
<div {...getRootProps()}>
<input {...getInputProps()} />
</div>
)}
</Dropzone>
)
const { container } = render(ui)
const dropzone = container.querySelector('div')
dispatchEvt(dropzone, 'dragenter', data)
await flushPromises(ui, container)
expect(onDragEnter).toHaveBeenCalled()
})
function flushPromises(ui, container) {
return new Promise(resolve =>
setImmediate(() => {
render(ui, { container })
resolve(container)
})
)
}
function dispatchEvt(node, type, data) {
const event = new Event(type, { bubbles: true })
Object.assign(event, data)
fireEvent(node, event)
}
function mockData(files) {
return {
dataTransfer: {
files,
items: files.map(file => ({
kind: 'file',
type: file.type,
getAsFile: () => file
})),
types: ['Files']
}
}
}
Note: using Enzyme for testing is not supported at the moment, see #2011.
More examples for this can be found in react-dropzone
s own test suites.
Support us with a monthly donation and help us continue our activities. [Become a backer]
Become a sponsor and get your logo on our README on Github with a link to your site. [Become a sponsor]
MIT
FAQs
Simple HTML5 drag-drop zone with React.js
We found that react-dropzone demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.